package handler

import (
	"net/http"
	"strings"
	"ywebgo/context"
)

type TrieHandler struct {
	root *Node
}

var supportMethods = [4]string{
	http.MethodGet,
	http.MethodPost,
	http.MethodPut,
	http.MethodDelete,
}

func (t *TrieHandler) Enroll(method string, pattern string, handleFunc HandleFunc) {
	curNode := t.getNodeByMethod(method)
	paths := trimAndSplit(pattern)

	for i, path := range paths {
		if childNode, found := curNode.match(path); found {
			curNode = childNode
		} else {
			curNode.createSubTrie(paths[i:], handleFunc)
			return
		}
	}
	curNode.handleFunc = handleFunc
}

func (t *TrieHandler) Handle(w http.ResponseWriter, r *http.Request) {
	curNode := t.getNodeByMethod(r.Method)
	paths := trimAndSplit(r.URL.Path)

	for _, path := range paths {
		if childNode, found := curNode.match(path); found {
			curNode = childNode
		} else {
			w.WriteHeader(http.StatusNotFound)
			_, _ = w.Write([]byte("Not Found"))
			return
		}
	}
	curNode.handleFunc(context.NewContext(w, r))
}

func (t *TrieHandler) getNodeByMethod(method string) *Node {
	for _, childNode := range t.root.children {
		if childNode.path == method {
			return childNode
		}
	}
	// TODO
	return nil
}

func trimAndSplit(pattern string) []string {
	pattern = strings.Trim(pattern, "/")
	paths := strings.Split(pattern, "/")
	return paths
}

func defaultMethods() []*Node {
	nodes := make([]*Node, len(supportMethods))
	for i, method := range supportMethods {
		nodes[i] = NewDefaultNode(method)
	}
	return nodes
}

func NewTrieHandler() *TrieHandler {
	return &TrieHandler{root: NewNode("/", defaultMethods())}
}
